home *** CD-ROM | disk | FTP | other *** search
-
- /*********************************************************************
-
- FILENAME
- Exceptions.h
-
- DESCRIPTION
- A collection of routines and macros to handle assertions and
- exceptions.
-
- COPYRIGHT
- Copyright © Apple Computer, Inc. 1989-1991
- All rights reserved.
-
- ROUTINES
- EXTERNALS
- dprintf
- check_dprintf
- checkpos_dprintf
-
- MACROS
- EXTERNALS
- check
- ncheck
- check_action
- ncheck_action
- require
- nrequire
- require_action
- nrequire_action
- resume
-
- MODIFICATION HISTORY
- 08/03/89 Sean Parent
- 1) Version 1.0d1 started
- 09/26/89 sp
- 1) Corrected the description of require
- 12/08/89 sp
- 1) Ported from XXXX Exceptions.h
- 03/16/90 sp
- 1) Removed refCon parameter
- 2) Added the "n" calls
- 05/10/90 sp
- 1) Added the dprintf call and revved other macros to use it.
- 06/12/90 sp
- 1) Modified the dprint off to use a macro for traceOption.
- 08/01/90 sp
- 1) Modified for C++ compatibility (Thanks Ron).
- 08/14/90 sp
- 1) Added action calls.
- 09/20/90 sp
- 1) Removed rescue_ prefix in require exception labels.
- 01/16/91 sp
- 1) Fixed some comments and updated the copyright notice.
- 02/13/91 sp
- 1) Added check_action and ncheck_action calls.
- 2) Added SetExceptionOption
- 02/22/91 sp
- 1) Added {} around all macros just to be defensive for TED.
- 2) Put everything in "if (true) { MACRO } else" form to be very
- defensive.
- 02/26/91 sp
- 1) Added a null statement after the else of each macro for the
- fools who forgot to put ; in.
- 03/13/91 sp
- 1) Added void* cast for privateAssertion for C++.
- 03/13/91 sp/NB
- 1) Fixed void* cast for privateAssertion for C++.
- 11/04/91 sp
- 1) Removed retry.
- 2) Added DEBUGMIN support.
- 3) Removed SetExceptionOption.
- 4) Cleaned up for Develop article.
- 11/05/91 sp
- 1) Removed PlaceHolder() and moved to "do { MACRO } while(false)"
- 11/19/91 sp
- 1) Added DEBUGSYM level.
-
- NOTE
- To keep code size down, use these routines and macros with the C
- compiler option -b2 or -b3. This will eliminate duplicate strings
- within a procedure.
-
- *********************************************************************/
-
- #ifndef __EXCEPTIONS__
- #define __EXCEPTIONS__
-
- /*********************************************************************
-
- INCLUDES
-
- *********************************************************************/
-
- #ifndef __TYPES__
- #include <Types.h>
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- CONSTANTS AND CONTROL
-
- *********************************************************************/
-
- /*
- These defines are used to control the amount of information
- displayed when an assertion fails. DEBUGOFF and WARN will run
- silently. MIN will simply break into the debugger. ON will break
- and display the assertion that failed and the exception (for
- require statements). FULL will also display the source file name
- and line number. SYM does a SysBreak and is usefull when using a
- symbolic debugger like SourceBug or SADE. They should be set into
- DEBUGLEVEL. The default LEVEL is OFF.
- */
-
- #define DEBUGOFF 0
- #define DEBUGWARN 1
- #define DEBUGMIN 2
- #define DEBUGON 3
- #define DEBUGFULL 4
- #define DEBUGSYM 6
- /*
- #ifndef DEBUGLEVEL
- #define DEBUGLEVEL DEBUGOFF
- #endif DEBUGLEVEL
- */
- /*
- resumeLabel is used to control the insertion of labels for use with
- the resume macro. If you do not use the resume macro and you wish
- to have multible exceptions per label then you can add the
- following define to you source code.
-
- #define resumeLabel(exception)
- */
-
- #define resumeLabel(exception) resume_ ## exception:
-
- /*
- trace and notrace are used for the traceOption for dprintf. If
- trace is used then the actual behavior can be controled from
- Macsbug. The macros in Macsbug are traceGo and traceBreak. traceGo
- is the default and execution will continue after the break. If
- traceBreak is used then execution will halt.
- */
-
- #define trace "\p;dprintf;doTrace"
- #define notrace "\p;dprintf"
-
- /*
- traceon and debugon are used to test for options
- */
-
- #define traceon ((DEBUGLEVEL > DEBUGWARN) && defined(TRACEON))
- #define debugon (DEBUGLEVEL > DEBUGWARN)
-
- /*
- Add some macros for DEBUGMIN and DEBUGSYM to keep the size down.
- */
-
- #define __DEBUGSMALL ((DEBUGLEVEL == DEBUGMIN) || \
- (DEBUGLEVEL == DEBUGSYM))
-
- #if DEBUGLEVEL == DEBUGMIN
- #define __DebuggerBreak Debugger()
- #elif DEBUGLEVEL == DEBUGSYM
- #define __DebuggerBreak SysBreak()
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- ROUTINE
- void dprintf(traceOption, format, ...)
-
- DESCRIPTION
- dprintf is used like printf only the information is displayed in
- MacsBug. traceOption is used to specify whether the execution
- should continue after the break or not. format contains
- two types of objects: ordinary characters, which are displayed in
- Macsbug, and coversion specifications, each of which causes
- conversion and printing of the next successive argument to dprintf.
- Each conversion specification begins with a % and ends with a
- conversion character. Between % and the conversion character there
- may be, in order:
-
- • Zero or more flag characters, which modify the meaning of the
- conversion specification.
- • A number that specifies the minimum field width. The converted
- argument will be printed in a field at least this wide. If
- necessary it will be padded on the left (or right, if left
- adjustment is called for) to make up the field width.
- • A period, which separates the field width from the precision.
- • A number, the precision, that specifies the maximum number of
- characters to be printed from a string, or the number of digits
- after the decimal point of a floatingpoint value, or the minimum
- number of digits for an integer.
- • An h if the integer is to be printed as a short, or l if as
- long (ignored since int is long), or L to specify that the
- following e, E, f, g, or G conversion is a long double.
-
- Note: A field width or precision may be indicated by an * instead
- of a digit string. In this case, an integer arg parameter supplies
- the field width or precision. The arg parameter that is actually
- converted is not fetched until the conversion letter is seen;
- therefore, the arg paramters specifying field width or precision
- must appear immediately before the arg parameter (if any) to be
- converted.
-
- The flag characters are:
-
- - The result of the conversion will be left justified
- within the field.
- + The result of a signed conversion always begins with a
- sign (+ or -).
- space If the first character of a signed conversion is not a
- sign, a space will be prefixed to the result. This implies
- that if the space and + flags both appear, the space flag
- will be ignored.
- # The value is to be converted to an alternate form. For c,
- d, s, and u conversions, the flag has no effect. For o
- conversions, it increases the precision to force the first
- digit of the result to be zero. For x, and X conversions,
- a nonzero result will have 0x or 0X prefixed to it. For
- e, E, f, g, and G conversions, the result will always
- contain a decimal point, even if no digits follow the
- point. For g and G conversion, trailing zeros in the
- fractional part will not be removed from the result.
- 0 The 0 flag pads the field with zeros on the left only;
- this applies to d, i, o, u, x, X, e, E, f, g, and G
- conversions. The leading zeros pad the field width, and
- no space padding is performed. If both the 0 and - flags
- appear, the 0 flag is ignored. If a precision is specified
- for d, i, o, u, x, and X conversions, the 0 flag is
- ignored.
-
- The standard conversions are:
-
- d,i int Decimal number.
- o int Unsigned octal number (w/o a leading zero).
- x,X int Unsigned hexadecimal number (w/o a leading 0x
- or oX), using abcdef or ABCDEF for 10,…,15.
- u int Unsigned decimal number.
- c int Single character.
- s char* C string.
- f double [-]m.dddddd, where the number of d's is given
- by the precision (default 6).
- e,E double [-]m.dddddde±xx or [-]m.ddddddE±xx, where the
- number of d's is given by the precision
- (default 6).
- g,G double Use %e or %E if the exponent is less than -4
- or greater than or equal to the precision;
- otherwise use %f. Trailing zeros and a
- trailing decimal point are not printed.
- p void* Pointer.
- % No argument is converted; print a %.
-
- The supported MPW extensions are:
-
- P StringPtr Pascal string.
-
- Of the MPW printf convertion characters only "n" is not supported.
- In addition to the standard characters, the following are defined:
-
- b Boolean Outputs either true or false.
- j Point Used like the d option.
- J point* Fixed point. Used like the f option.
- F Fixed Used like the f option.
- T Fract Used like the f option.
- r Rect* Displays the rect with each piece seperated by
- ", ". Used like the d option.
- R rectangle* Similar to r but for fixed point rectangles.
- Used like the f option.
- M mapping. Displays the mapping seperated by ", " and
- "\n". The third column is displayed as fract.
- Used like the f option.
-
-
- dprintf requires that the MacsBug dcmd dprintf is present.
-
- Characters used: bcdefghij l nop rs u x
- EFG J LM P R T X
- Not used: a k m q t vw yz
- ABCD HI K NO Q S UVW YZ
-
- See the MPW C Reference for more information on printf.
-
- Echo " ∂n∂
- PRINT OFF,NOHDR ∂n∂
- INCLUDE 'Traps.a' ∂n∂
- PRINT ON ∂n∂
- PROC ∂n∂
- _DebugStr ∂n∂
- SUBQ #4,SP ; Fix the stack ∂n∂
- ENDPROC ∂n∂
- END ∂n∂
- " | Asm -l
-
- *********************************************************************/
-
- void dprintf(StringPtr, char[], ...)
- = { 0xABFF, 0x594F };
-
- /*<FF>*/
- /*********************************************************************
-
- ROUTINE
- void* check_dprintf(assertion, traceOption, format, ...)
-
- DESCRIPTION
- If assertion is non-zero then assertion is returned. Otherwise the
- dprintf is invoked and zero is returned.
-
- Echo " ∂n∂
- PRINT OFF,NOHDR ∂n∂
- INCLUDE 'Traps.a' ∂n∂
- PRINT ON ∂n∂
- PROC ∂n∂
- MOVE.L (SP)+,D0 ; Pop value into D0 ∂n∂
- BNE.S @1 ; If !0 then branch ∂n∂
- _DebugStr ∂n∂
- SUBQ #4,SP ; Fix the stack ∂n∂
- CLR.W D0 ; Result is zero ∂n∂
- @1 SUBQ #4,SP ; Fix stack for pop ∂n∂
- ENDPROC ∂n∂
- END ∂n∂
- " | Asm -l
-
- *********************************************************************/
-
- void* check_dprintf(void*, StringPtr, char[], ...) =
- { 0x201F, 0x6606, 0xABFF, 0x594F, 0x4240, 0x594F };
-
- /*<FF>*/
- /*********************************************************************
-
- ROUTINE
- void* checkpos_dprintf(assertion, traceOption, format, ...)
-
- DESCRIPTION
- If assertion is positive then assertion is returned. Otherwise the
- dprintf is invoked and zero is returned.
-
- Echo " ∂n∂
- PRINT OFF,NOHDR ∂n∂
- INCLUDE 'Traps.a' ∂n∂
- PRINT ON ∂n∂
- PROC ∂n∂
- MOVE.L (SP)+,D0 ; Pop value into D0 ∂n∂
- BGE.S @1 ; If >= 0 then branch ∂n∂
- _DebugStr ∂n∂
- SUBQ #4,SP ; Fix the stack ∂n∂
- CLR.W D0 ; Result is zero ∂n∂
- @1 SUBQ #4,SP ; Fix stack for pop ∂n∂
- ENDPROC ∂n∂
- END ∂n∂
- " | Asm -l
-
- *********************************************************************/
-
- void* checkpos_dprintf(void*, StringPtr, char[], ...) =
- { 0x201F, 0x6C06, 0xABFF, 0x594F, 0x4240, 0x594F };
-
- /*<FF>*/
- /*********************************************************************
-
- MACRO
- check(assertion)
-
- DESCRIPTION
- If debugging is on then check will test assertion and if it fails
- break into the debugger. Otherwise check does nothing.
-
- *********************************************************************/
-
- #if __DEBUGSMALL
-
- #define check(assertion) \
- do { \
- if (assertion) ; \
- else __DebuggerBreak; \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGON
-
- #define check(assertion) \
- do { \
- if (assertion) ; \
- else { \
- dprintf(notrace, "Assertion \"%s\" Failed", #assertion); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGFULL
-
- #define check(assertion) \
- do { \
- if (assertion) ; \
- else { \
- dprintf(notrace, "Assertion \"%s\" Failed\n" \
- "File: %s\n" \
- "Line: %d", \
- #assertion, __FILE__, __LINE__); \
- } \
- } while (false)
-
- #else
-
- #define check(assertion)
-
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- MACRO
- ncheck(assertion)
-
- DESCRIPTION
- If debugging is on then ncheck will test !assertion and if it fails
- break into the debugger. Otherwise ncheck does nothing.
-
- *********************************************************************/
-
- #if __DEBUGSMALL
-
- #define ncheck(assertion) \
- do { \
- if (assertion) __DebuggerBreak; \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGON
-
- #define ncheck(assertion) \
- do { \
- void* __privateAssertion = (void*)(assertion); \
- \
- if (__privateAssertion) { \
- dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed", \
- #assertion, __privateAssertion); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGFULL
-
- #define ncheck(assertion) \
- do { \
- void* __privateAssertion = (void*)(assertion); \
- \
- if (__privateAssertion) { \
- dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
- "File: %s\n" \
- "Line: %d", \
- #assertion, __privateAssertion, __FILE__, __LINE__); \
- } \
- } while (false)
-
- #else
-
- #define ncheck(assertion)
-
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- MACRO
- check_action(assertion, action)
-
- DESCRIPTION
- If debugging is on then check_action will test assertion and if it
- fails break into the debugger then execute action. Otherwise
- check_action does nothing.
-
- *********************************************************************/
-
- #if __DEBUGSMALL
-
- #define check_action(assertion, action) \
- do { \
- if (assertion) ; \
- else { \
- __DebuggerBreak; \
- { action } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGON
-
- #define check_action(assertion, action) \
- do { \
- if (assertion) ; \
- else { \
- dprintf(notrace, "Assertion \"%s\" Failed", #assertion); \
- { action } \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGFULL
-
- #define check_action(assertion, action) \
- do { \
- if (assertion) ; \
- else { \
- dprintf(notrace, "Assertion \"%s\" Failed\n" \
- "File: %s\n" \
- "Line: %d", \
- #assertion, __FILE__, __LINE__); \
- { action } \
- } \
- } while (false)
-
- #else
-
- #define check_action(assertion, action)
-
- #endif
-
- /*<FF>*/
- /**************************************************************************************
-
- MACRO
- ncheck_action(assertion, action)
-
- DESCRIPTION
- If debugging is on then ncheck_action will test !assertion and if
- it fails break into the debugger then execute action. Otherwise
- ncheck_action does nothing.
-
- *********************************************************************/
-
- #if __DEBUGSMALL
-
- #define ncheck_action(assertion, action) \
- do { \
- if (assertion) { \
- __DebuggerBreak; \
- { action } \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGON
-
- #define ncheck_action(assertion, action) \
- do { \
- void* __privateAssertion = (void*)(assertion); \
- \
- if (__privateAssertion) { \
- dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed", \
- #assertion, __privateAssertion); \
- { action } \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGFULL
-
- #define ncheck_action(assertion, action) \
- do { \
- void* __privateAssertion = (void*)(assertion); \
- \
- if (__privateAssertion) { \
- dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
- "File: %s\n" \
- "Line: %d", \
- #assertion, __privateAssertion, __FILE__, __LINE__); \
- { action } \
- } \
- } while (false)
-
- #else
-
- #define ncheck_action(assertion, action)
-
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- MACRO
- require(assertion, exception)
-
- DESCRIPTION
- require will test assertion and if it fails:
- break into the debugger if debugging is on.
- goto exception.
-
- *********************************************************************/
-
- #if __DEBUGSMALL
-
- #define require(assertion, exception) \
- do { \
- if (assertion) ; \
- else { \
- __DebuggerBreak; \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGON
-
- #define require(assertion, exception) \
- do { \
- if (assertion) ; \
- else { \
- dprintf(notrace, "Assertion \"%s\" Failed\n" \
- "Exception \"%s\" Raised", \
- #assertion, #exception); \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGFULL
-
- #define require(assertion, exception) \
- do { \
- if (assertion) ; \
- else { \
- dprintf(notrace, "Assertion \"%s\" Failed\n" \
- "Exception \"%s\" Raised\n" \
- "File: %s\n" \
- "Line: %d", \
- #assertion, #exception, __FILE__, __LINE__); \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #else
-
- #define require(assertion, exception) \
- do { \
- if (assertion) ; \
- else { \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- MACRO
- nrequire(assertion, exception)
-
- DESCRIPTION
- nrequire will test !assertion and if it fails:
- break into the debugger if debugging is on.
- goto exception.
-
- *********************************************************************/
-
- #if __DEBUGSMALL
-
- #define nrequire(assertion, exception) \
- do { \
- if (assertion) { \
- DebugStr(); \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGON
-
- #define nrequire(assertion, exception) \
- do { \
- void* __privateAssertion = (void*)(assertion); \
- \
- if (__privateAssertion) { \
- dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
- "Exception \"%s\" Raised", \
- #assertion, __privateAssertion, #exception); \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGFULL
-
- #define nrequire(assertion, exception) \
- do { \
- void* __privateAssertion = (void*)(assertion); \
- \
- if (__privateAssertion) { \
- dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
- "Exception \"%s\" Raised\n" \
- "File: %s\n" \
- "Line: %d", \
- #assertion, __privateAssertion, #exception, __FILE__, \
- __LINE__); \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #else
-
- #define nrequire(assertion, exception) \
- do { \
- if (assertion) { \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- MACRO
- require_action(assertion, exception, action)
-
- DESCRIPTION
- require_action will test assertion and if it fails:
- break into the debugger if debugging is on.
- execute action.
- goto exception.
-
- *********************************************************************/
-
- #if __DEBUGSMALL
-
- #define require_action(assertion, exception, action) \
- do { \
- if (assertion) ; \
- else { \
- __DebuggerBreak; \
- { action } \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGON
-
- #define require_action(assertion, exception, action) \
- do { \
- if (assertion) ; \
- else { \
- dprintf(notrace, "Assertion \"%s\" Failed\n" \
- "Exception \"%s\" Raised", \
- #assertion, #exception); \
- { action } \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGFULL
-
- #define require_action(assertion, exception, action) \
- do { \
- if (assertion) ; \
- else { \
- dprintf(notrace, "Assertion \"%s\" Failed\n" \
- "Exception \"%s\" Raised\n" \
- "File: %s\n" \
- "Line: %d", \
- #assertion, #exception, __FILE__, __LINE__); \
- { action } \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #else
-
- #define require_action(assertion, exception, action) \
- do { \
- if (assertion) ; \
- else { \
- { action } \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- MACRO
- nrequire_action(assertion, exception, action)
-
- DESCRIPTION
- nrequire_action will test !assertion and if it fails:
- break into the debugger if debugging is on.
- execute action.
- goto exception.
-
- *********************************************************************/
-
- #if __DEBUGSMALL
-
- #define nrequire_action(assertion, exception, action) \
- do { \
- if (assertion) { \
- __DebuggerBreak; \
- { action } \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGON
-
- #define nrequire_action(assertion, exception, action) \
- do { \
- void* __privateAssertion = (void*)(assertion); \
- \
- if (__privateAssertion) { \
- dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
- "Exception \"%s\" Raised", \
- #assertion, __privateAssertion, #exception); \
- { action } \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #elif DEBUGLEVEL == DEBUGFULL
-
- #define nrequire_action(assertion, exception, action) \
- do { \
- void* __privateAssertion = (void*)(assertion); \
- \
- if (__privateAssertion) { \
- dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \
- "Exception \"%s\" Raised\n" \
- "File: %s\n" \
- "Line: %d", \
- #assertion, __privateAssertion, #exception, __FILE__, \
- __LINE__); \
- { action } \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #else
-
- #define nrequire_action(assertion, exception, action) \
- do { \
- if (assertion) { \
- { action } \
- goto exception; \
- resumeLabel(exception); \
- } \
- } while (false)
-
- #endif
-
- /*<FF>*/
- /*********************************************************************
-
- MACRO
- resume(exception)
-
- DESCRIPTION
- resume will resume execution after the n/require/_action statement
- specified by exception. Resume lables must be on (the default) in
- order to use resume. If an action form of require was used then the
- action will not be re-executed.
-
- *********************************************************************/
-
-
- #define resume(exception) \
- do { \
- goto resume_ ## exception; \
- } while (false)
-
-
- /*<FF>*/
- /********************************************************************/
-
- #endif